#pragma once
#include <iostream>
#include <string>
#include <cstring>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <functional>
#include "Log.hpp"
// 本质上只有一个.cc的源文件，所以不需要定义外部变量，
// 因为所有的头文件都会被展开到这一个源文件中，直接定义就好了


//两种写法等价，方法里的返回值和参数
//using func_t=std::function<std::string(const std::string&)>;
typedef std::function<std::string(std::string&)> func_t;

Log logger;
enum
{
    SOCKET_ERR=1,
    BIND_ERR
};

std::string defaultip="0.0.0.0";
uint16_t defaultport=8080;
const int size=1024;

class udpServer
{
public:
    udpServer(const uint16_t port=defaultport,const std::string& ip=defaultip)
    :_sockfd(0)
    ,_ip(ip)
    ,_port(port)
    ,_isrunning(false)
    {}
    void Init()
    {
        //1.创建套接字
        _sockfd=socket(AF_INET,SOCK_DGRAM,0);
        if(_sockfd<0)
        {
            logger(Fatal,"create socket errno: %d,errstring: %s",errno,strerror(errno));
            exit(SOCKET_ERR);
        }
        logger(Info,"sockfd create success,sockfd:%d",_sockfd);
        //2.绑定套接字
        struct sockaddr_in local;           
        bzero(&local,sizeof(local));                
        local.sin_family=AF_INET;
        local.sin_port=htons(_port);       //因为该端口号是要给对方发送的所以要保证端口号是网络字节序列
        // local.sin_addr.s_addr =inet_addr(_ip.c_str());     //必须把字符串转成uint32_t，网络序列
        local.sin_addr.s_addr=INADDR_ANY;             //也可以这样写，绑定任意ip
        int n=bind(_sockfd,(const struct sockaddr*)&local,sizeof(local));
        if(n<0)
        {
            logger(Fatal,"bind error,errno:%d,string:%s",errno,strerror(errno));
            exit(BIND_ERR);
        }
        logger(Info,"bind success,errno:%d,string:%s",errno,strerror(errno));
    }

    //对代码进行分层
    void Run(func_t func)
    {
        _isrunning=true;
        char inbuf[size];
        while(_isrunning)
        {
            struct sockaddr_in client;
            memset(&client,0,sizeof(client));
            socklen_t len=sizeof(client);

            //3.记录客户端发来的信息
            ssize_t n =recvfrom(_sockfd,inbuf,sizeof(inbuf) - 1,0,(struct sockaddr*)&client,&len);  //客户的数据，客户是谁
            if(n<0)
            {
                logger(Warrning,"recvfrom error,error:%d,err string:%s",errno,strerror(errno));
                continue;
            }
            inbuf[n]=0;                 //清空
            std::string info=inbuf;     //放入用户数据
            std::string echo_string=func(info);        //服务端做处理返回给客户端

            std::cout<<echo_string<<std::endl;

            4//.给客户端传回信息
            sendto(_sockfd,echo_string.c_str(),echo_string.size(),0,(const sockaddr*)&client,len);
            std::cout<<"like a plant,friendship will wither if neglected"<<std::endl;
        }   
    }

    ~udpServer()
    {
        if(_sockfd>0) close(_sockfd);
    }
private:
    int _sockfd;            //网络文件描述符
    std::string _ip;        //任意地址bind 0
    uint16_t _port;         //服务器进程端口号
    bool _isrunning;
};